<?php

namespace app\index\service;

use app\common\model\AccountTokenPlan;
use app\common\model\Trade;
use app\common\model\Transfer;
use app\common\service\TransfersServer;
use app\index\dao\TradeDao;
use app\index\model\UM as UM;
use app\index\service\payments\CardPaymentService;
use app\index\service\payments\CoinPaymentService;
use think\exception\ValidateException;
use think\facade\Config;

/**
 * Class BalanceRechargeService
 * @package app\index\service
 */
class TradeTokenRechargeService implements TradableInterface, TransferableInterface
{
    // dao
    private TradeDao $tradeDao;

    public function __construct(TradeDao $tradeDao)
    {
        $this->tradeDao = $tradeDao;
    }

    /**
     * 新增
     * @param UM $user
     * @param array $params
     * @return  \app\common\model\Trade
     */
    public function add(UM $user, array $params): Trade
    {
        // 补齐参数，创建Trade
        $tradeType = TRADE_TOKEN_RECHARGE;
        $tradeConfig = Config::get("trade.trades.$tradeType", []);
        $tradeTypeClass = $tradeConfig['className'] ?? '';

        // 渠道链路
        ['pf' => $pf, 'chain' => $chain, 'promotionGroupId' => $promotionGroupId] = getChainParams();

        // 推广回传
        $promotionFeedback = $params['promotionFeedback'] ?? null;

        $planId = $params['planId'] ?? null;
        if (!is_id($planId)) {
            throw new ValidateException('请选择一个套餐');
        }
        $plan = AccountTokenPlan::where('id', $planId)->find();
        if (is_null($plan)) {
            throw new ValidateException('该套餐不存在或已被删除');
        }

        // 检查用户的代币账户是否可用
        if ($plan->card > 0) {
            if (!$this->getCardPaymentService()->isEnableTransfer($user->id)) {
                throw new ValidateException('您的获客卡账户暂时不可用，请联系管理员');
            }
        }
        if ($plan->coin > 0) {
            if (!$this->getCoinPaymentService()->isEnableTransfer($user->id)) {
                throw new ValidateException('您的通信币账户暂时不可用，请联系管理员');
            }
        }

        $describe = $tradeConfig['name'] . ' ' . $plan->name;

        // 暂时没说优惠卷
        $showMoney = $plan->price;
        $totalMoney = $plan->price;
        $payMoney = $totalMoney;
        $settleStatus = Trade::UNSETTLED;

        $phones = array_merge(Config::get('member.developerAccount', []), Config::get('member.testAccount', []));
        if (in_array($user->phone, $phones)) {
            $payMoney = '0.01';
            $settleStatus = Trade::NOTSETTLE;
        }

        if ($payMoney < 0.01) {
            throw new ValidateException('订单价格应该大于0');
        }

        $tradeParams = [
            'memberId' => $user->id,
            'orderNoPre' => 'TR',
            'describe' => $describe,
            'tradeType' => $tradeType,
            'tradeTypeClass' => $tradeTypeClass,
            'accountTokenPlanId' => $planId,
            'showMoney' => $showMoney,
            'totalMoney' => $totalMoney,
            'payMoney' => $payMoney,
            'payStatus' => Trade::UNPAID,
            'payExpTime' => time() + 3600,
            'settleStatus' => $settleStatus,
            'pf' => $pf,
            'chain' => $chain,
            'promotionGroupId' => $promotionGroupId,
            'attach' => [
                'attach' => '',
                'promotionFeedback' => $promotionFeedback,
            ],
        ];

        $record = $this->tradeDao->insertTrade($tradeParams);

        // 触发订单创建时间
        event('TradeCreated', $record);

        return $record;
    }

    // 完成订单
    public function completionTrade(Trade $trade)
    {
        $planId = $trade->accountTokenPlanId;
        if (!is_id($planId)) {
            // TODO 记录错误
            return;
        }
        $plan = AccountTokenPlan::where('id', $planId)->find();
        if (is_null($plan)) {
            // TODO 记录错误
            return;
        }

        // 设置服务开始和完成时间
        $time = time();
        $trade->startTime = $time;
        $trade->save();

        // 直接插入一条转账申请
        $this->createTransfer($trade, $plan);

        // 推广事件回传
        $this->getPromotionCallbackService()->push($trade);

        // 触发订单完成事件
        event('TradeEnded', $trade);
    }

    // 完成退款
    public function completionRefundTrade(Trade $trade)
    {
        throw new ValidateException('获客卡&通信币充值订单不能退款');

        return;
    }

    public function canceledTrade(Trade $trade)
    {
        return;
    }

    // 完成转账
    public function completionTransfer(Transfer $transfer): void
    {
        // 充值转账完成后，没有后续逻辑了，但还是给个空方法，方便回调使用
        return;
    }

    /**
     * 创建转账申请
     * @param Trade $trade
     * @return void
     */
    private function createTransfer(Trade $trade, AccountTokenPlan $plan)
    {
        // 获客卡充值
        if ($plan->card > 0) {

            $transferType = TRANSFER_CARD_RECHARGE;
            $payMethod = TRANSFER_CARD;
            $memberId = $trade->memberId;
            $accountNumber = $trade->memberId;
            $describe = $trade->describe;
            $totalMoney = $plan->card;
            $append = [
                'tradeId' => $trade->id,
                'accountTokenPlanId' => $plan->id,
            ];
            $this->getTransfersServer()->pushTransferToMember($transferType, $memberId, $payMethod, $accountNumber, $totalMoney, $describe, $append);
        }

        // 通信币充值
        if ($plan->coin > 0) {

            $transferType = TRANSFER_COIN_RECHARGE;
            $payMethod = TRANSFER_COIN;
            $memberId = $trade->memberId;
            $accountNumber = $trade->memberId;
            $describe = $trade->describe;
            $totalMoney = $plan->coin;
            $append = [
                'tradeId' => $trade->id,
                'accountTokenPlanId' => $plan->id,
            ];
            $this->getTransfersServer()->pushTransferToMember($transferType, $memberId, $payMethod, $accountNumber, $totalMoney, $describe, $append);
        }

    }

    private function getCardPaymentService(): CardPaymentService
    {
        return app(CardPaymentService::class);
    }

    private function getCoinPaymentService(): CoinPaymentService
    {
        return app(CoinPaymentService::class);
    }

    private function getTransfersServer(): TransfersServer
    {
        return app(TransfersServer::class);
    }

    private function getPromotionCallbackService(): \app\common\service\PromotionCallbackService
    {
        return app(\app\common\service\PromotionCallbackService::class);
    }
}
